#!usr/bin/env python
# -*- coding:utf-8 -*-

import os
import re
import logging
import shutil
from xml.etree import ElementTree as ET
from xml.etree.ElementTree import ParseError as XmlParseError
from commFunc import *
from lxml import etree
from edtXLS import wt_case_xls_file
from public_parameters import CAPRESOURCE_PATH
from public_parameters import TEST_RESULT_PATH1
from public_parameters import PRNCFGDYN2_NAME

console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('[%(asctime)s]:%(levelname)-7s %(filename)s:%(lineno)s- %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)


'''
    To find the ELEMENT`s attribute
    xmlpath: Cap file path,like:C:\Users\lianghailun.BEYONDSOFT\Desktop\capResource\ProductConfigCap.xml;
    nodename: test example (Ticket name) from work dir files; like 'Accuracy.txt';
    parentname:Accuracy`s parentname;
    childrenname:Accuracy`s childrenname;
    attribute:dict type,Accuracy`s attribute;
'''

class PARSXML(object):
    '''
    parsxml
    '''
    def __init__(self, nodename, xmlFileOrContent):
        self.nodename = nodename
        self.xmlFileOrContent = xmlFileOrContent
        try:
            self.per = ET.parse(self.xmlFileOrContent)
            tree = etree.parse(self.xmlFileOrContent)
            self.root = tree.getroot()
        except IOError as e:
            try:
                self.per = ET.fromstring(self.xmlFileOrContent)
                self.root = etree.fromstring(self.xmlFileOrContent)
            except Exception as e:
                logging.error("Format not valid:%s",str(e))
                self.per = ET.fromstring(self.xmlFileOrContent)
                self.root = etree.HTML(self.xmlFileOrContent)

    def __ge__(self, other):
        return cmp_lst(self.get_element_text(), other.get_element_text())

    def is_valide_file(self):
        if not isinstance(self.xmlFileOrContent, basestring):
            return False
        if not os.path.exists(os.path.realpath(self.xmlFileOrContent)):
            logging.error("The filepath:%s is not exist." % self.xmlFileOrContent)
            return False
        if not os.path.isfile(self.xmlFileOrContent):
            logging.error("The path:%s is not a file." % self.xmlFileOrContent)
            return False
        return True
    
    def get_p(self, nodename=None):
        if not nodename:
            nodename=self.nodename.split("/")[-1]
        else:
            nodename=nodename.split("/")[-1]
        try:
            p = self.per.findall(".//" + nodename)
        except SyntaxError as e:
            try:       
                p = self.per.findall(".//" + nodename, namespaces=self.get_ns())
            except Exception as e:
                return []
        return p
    
    def get_ns(self):    
        return self.root.nsmap
    
    def is_enum(self):
        if len(self.get_p()) == 0: return 
        #return True if len(self.get_p()) != 1 else False    
        for oneper in self.get_p():
            if oneper.attrib == {}:
                return True
            else:
                return False
    
    def get_access(self, ndnm=None):
        if not ndnm: ndnm = self.nodename
        if len(self.get_p(nodename=ndnm)) == 0: return 
        else:
            for oneper in self.get_p(nodename=ndnm):
                if oneper.attrib.has_key('access'):
                    return oneper.attrib['access']
                else:
                    ndnm = ndnm +'/..'
                    return self.get_access(ndnm)
    
    def get_element_text(self, ndnm=None):
        texts_of_element = []
        if not ndnm: ndnm = self.nodename
        if len(self.get_p(nodename=ndnm)) == 0: return texts_of_element
        for oneper in self.get_p(nodename=ndnm):
            texts_of_element.append(oneper.text)
        return texts_of_element
    
    def get_node_attr(self):
        tmp_attr = {"access": "",
                    "typeof": "",
                    "length": "",
                    "min": "",
                    "max": "",
                    "step": "",
                    "enum_Value": [],
                    "invalid_enum_Value": [],
                    "selected": "",
                    "deselected": "",
                    "elementXPath": ""}
        cur_attr = tmp_attr
        if self.is_enum():
            cur_attr["access"] = self.get_access()
            #self.get_p() = [perObj1, perObj2, perObj3,]
            for oneper in self.get_p():
                cur_attr["enum_Value"].append(oneper.text)
                cur_attr["typeof"] = 'xx:enum'
            return cur_attr
        else:
            #self.get_p() = [perObj,]
            for oneper in self.get_p():
                tmp = oneper.attrib
                try:
                    for tmp_key in tmp.keys():
                        if tmp_key in cur_attr.keys():
                            cur_attr[tmp_key] = tmp.get(tmp_key)
                        else:
                            print "Unused key:%s was in Cap file, element:%s." % (tmp_key, oneper.tag)
                    if cur_attr['access'] == '': cur_attr['access'] = self.get_access()
                    
                    return cur_attr
                except Exception as e:
                    print "Occure exception:%s" % str(e)
                    
        
'''
    function:compare node texts from two files;
    @nodename: the name of a node to be compared, e.g:"dd:Faxinteger";
    @capfile: CAP file in path: %LEDM%/capResource, file;
    @resfile_cont: http request result, str;
'''
class cmpReqRsult():
    def __init__(self, nodename, capfile, ticketfile, resfileContent):
        self.nodename = nodename
        self.capfile = capfile
        self.ticketfile = ticketfile
        self.resfileContent = self._normalize_file_2_content(resfileContent)
        self.capxml_obj = None

    def _normalize_file_2_content(self, resfileContent):
        if isinstance(resfileContent, file):
            return resfileContent.read()
        if isinstance(resfileContent, str) or isinstance(resfileContent, unicode):
            return resfileContent

    def __xpath_in_capfile(self):

        if not self.capxml_obj:
            #----------------修改获取.xml的路径的方式---------------------（Jerry feng2017-4-7）
            #self.capxml_obj = PARSXML(self.nodename.split("/")[-1], self.capfile)
            self.capxml_obj = PARSXML(self.nodename.split("/")[-1], os.path.join(TEST_RESULT_PATH1, self.nodename.split("/")[0] + ".xml"))
            #----------------修改获取.xml的路径的方式---------------------（Jerry feng2017-4-7）

        return "/" + self.capxml_obj.get_node_attr().get("elementXPath", "")
    
    def __text_in_tktf(self):

        ndnm_in_ticket = self.__xpath_in_capfile().split('/')[-1]
         #----------------就Ticket中存在的特殊情况（节点名称不一致）以if-elif-else的形式分别处理（针对Request返回后的值）---------------------（Jerry feng2017-4-7）
        if ndnm_in_ticket != "":
            parstktxml = PARSXML(ndnm_in_ticket, self.ticketfile)
            return parstktxml.get_element_text()
        else:
            nodename1 = str(self.nodename).split("/")[-1]
            nodename2 = nodename1.split(":")[0]
            nodename3 = nodename1.split(":")[-1]

            if "cap" in nodename2:
                nodename4 = nodename2.split("cap")[0]
                nodename5 = nodename4 + "dyn"
                ndnm_in_ticket = nodename5 + ":" + nodename3
                if nodename3 in PRNCFGDYN2_NAME:
                    ndnm_in_ticket = nodename5 + "2:" + nodename3
            elif "sjc" in nodename2:
                ndnm_in_ticket = "sj:" + nodename3
            else:
                ndnm_in_ticket = nodename1
            parstktxml = PARSXML(ndnm_in_ticket, self.ticketfile)
            #----------------就Ticket中存在的特殊情况（节点名称不一致）以if-elif-else的形式分别处理（针对Request返回后的值）---------------------（Jerry feng2017-4-7）
            return parstktxml.get_element_text()
    def __text_in_resf(self):
        res_node_text= []
        root = etree.XML(self.resfileContent)
        ns = root.nsmap

        res_node_obj = root.xpath(self.__xpath_in_capfile(), namespaces=ns)
        for i in res_node_obj:
            res_node_text.append(i.text)

        if res_node_text == []:

            ndnm_in_ticket1 = self.__xpath_in_capfile().split('/')[-1]
            try:
                str1 = str(self.resfileContent).split('<' + ndnm_in_ticket1 + '>')[1].split('</' + ndnm_in_ticket1 + '>')
                del str1[1]
                res_node_text = str1
            except Exception as e:
                #----------------就Ticket中存在的特殊情况以if-else的形式分别处理（这针对ticket中txt中的内容，即正常情况无法获取时）---------------------（Jerry feng2017-4-7）
                nodename1 = str(self.nodename).split(":")[-1]
                if nodename1 == "IPAddress":
                    nodename2 = nodename1 + ' xsi:nil="true"'
                    str1 = str(self.resfileContent).split(nodename2 + '>')[1].split('</')
                else:
                    str1 = str(self.resfileContent).split(nodename1 + '>')[1].split('</')
                del str1[1]
                res_node_text = str1
            #----------------就Ticket中存在的特殊情况以if-else的形式分别处理（这针对ticket中txt中的内容，即正常情况无法获取时）---------------------（Jerry feng2017-4-7）
        return res_node_text

    def text_is_qual(self):

        return cmp_lst(self.__text_in_tktf(), self.__text_in_resf())
    
    
def generate_ticket_file(txtfile,xmlfile):
    nodename = os.path.basename(os.path.realpath(txtfile)).split('.')[0]
    if nodename.count('_') != 1: raise Exception("tickets template name should be xxx_xxx.txt")
    nodename = nodename.replace('_', ':')
    mycontent = {}
    attribute ={}
    elementInfo = PARSXML(nodename, xmlfile)
    if elementInfo.is_valide_file():
        try:
            attribute = elementInfo.get_node_attr()
            #enum_Value = attribute['enum_Value']
            tp = attribute['typeof'].split(':')[-1]
            logging.info("We have a type:[%s]." % tp)
        except SyntaxError as e:
            logging.warn(str(e)+", and file name is:%s.txt" % nodename)
            return
        except TypeError as e:
            logging.warn("element:[%s] may not found in cap file." % nodename)
            return

        if tp.lower() == 'enum':

            access = attribute.get("access", None)
            enum_Value = attribute['enum_Value']

            mycontent = gen_attr_enum("enum", attribute['enum_Value'])
            write_to_file(txtfile, nodename.split(":")[-1], mycontent, access)
        elif tp.lower() in ["string", "double", "integer", "int","nonnegativeinteger","positiveinteger","enabledisable","boolean"]:
            len_string = attribute.get("length", None)
            min_num = attribute.get("min", None)
            max_num = attribute.get("max", None)
            step_num = attribute.get("step", None)
            access = attribute.get("access", None)
            selected = attribute.get("selected", None)
            deselected = attribute.get("deselected", None)
            # {thetp: {inOknum:"OK", inNoknum:"NOK", outNoknum:"NOK" }} ---double, int, intager
            # {thetp:{myStr1:"OK", myStr2:"NOK"}}  ---string
            mycontent = gen_attr_values(tp, len_string, min_num, max_num, step_num, selected, deselected)
            write_to_file(txtfile, nodename.split(":")[-1], mycontent, access)
        else:
            logging.warn("Find a new type:[%s]." % tp)
    else:
        logging.warn("xmlfile is not invalid, exit.")
    return


def write_to_file(fl, nodename, content, access):
    if not fl.endswith('txt'):
        logging.info("Current file is not a valid txt file, may be exception.")
    #     pattern_of_element = re.compile("<\w+:%s\>(.*?)\<\/\w+:%s\>" % nodename)
    logging.info("Begin to write txt files...")
    file_prefix = 0
    for k1, v1 in content.items():
        for k2, v2 in v1.items():
            destfile = fl.split('.')[0] +"_%s_%s_%s.txt" % (v2, access, file_prefix)
            file_prefix += 1
            shutil.copy(fl, destfile)
            try:
                with open(fl, 'r') as fpr:
                    with open(destfile,'w') as fpw:
                        for line in fpr.readlines():
                            if line.split(":")[-1].rstrip() == nodename+">":
                                line = re.sub("\>(.*?)\<",r'>%s<' % str(k2), line)
                            fpw.write(line)
            except Exception as e:
                logging.error("Exception: %s" % str(e))
            logging.info("Edit element text to [%s] end." % str(k2))
        logging.info("Write txt file:%s complete." % destfile)

def gen_file():
    
    for xmlfile in getfilelist(CAPRESOURCE_PATH, []):
        capfolder = os.path.basename(xmlfile).split(".")[0]
        ticketDir = os.path.realpath(os.path.join('.', 'testMaterial','Tickets'))
        if not xmlfile.endswith('xml') or not checkpath(ticketDir, capfolder):
            logging.warn("check ticket path fail, ignore")
            continue

        txtfilePath = os.path.realpath(os.path.join('.', 'testMaterial','Tickets', capfolder))
        for txtfile in getfilelist(txtfilePath, []):
            if txtfile.endswith('txt') and not os.path.basename(txtfile).count('_') == 3:
                try:
                    ET.parse(txtfile)
                    generate_ticket_file(txtfile,xmlfile)
                except ET.ParseError as e:
                    logging.error("Tickets template file[%s] is not valid! %s" % (txtfile, str(e)))
                finally:
                    logging.info("Remove txt file[%s]." % txtfile)
                    os.remove(txtfile)
        try:
            wt_case_xls_file(capfolder)
        except Exception as e:
            logging.error("Fail to save excel, Exception: %s" % str(e))
if __name__ == '__main__':
#     nodename = "nacap:ApplicationServiceName"
#     capfile = r"C:\Users\lianghailun.BEYONDSOFT\Desktop\xx\NetAppsCap.xml"
#     resfile = r"C:\Users\lianghailun.BEYONDSOFT\Desktop\xx\res.xml"
#     ticketfile = r"C:\Users\lianghailun.BEYONDSOFT\Desktop\xx\tickets.xml"
#     s = cmpReqRsult(nodename, capfile, ticketfile, resfile)
#     print s.text_is_qual()
    gen_file()